﻿using CaseManagerLibrary.Models;
using NetSDKCS;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace CaseManagerLibrary.Socket
{
    public delegate void ReceivedAsyncEventHandler(string message, TcpClientState state);
    public class TcpManagerAsync
    {
        private TcpListener listener;

        public delegate void ReceivedEventHandler(string message, IPEndPoint remoteEp);
        public event ReceivedAsyncEventHandler Received;

        private IPEndPoint localEp;
        private Thread socketThread;

        public event EventHandler Started;

        private Dictionary<string, TcpClientState> connections;

        private static object lock_conn = new object();

        public bool IsRunning { get; private set; }


        public TcpManagerAsync(IPEndPoint bindEp)
        {
            localEp = bindEp;

            listener = new TcpListener(localEp);

            listener.AllowNatTraversal(true);

            connections = new Dictionary<string, TcpClientState>();

        }

        public void Start()
        {
            if (!IsRunning)
            {
                IsRunning = true;
                listener.Start();
                listener.BeginAcceptTcpClient(new AsyncCallback(HandleTcpClientAccepted), listener);
            }
        }

        /// <summary>
        /// 停止服务器
        /// </summary>
        public void Stop()
        {
            if (IsRunning)
            {
                IsRunning = false;
                listener.Stop();
            }
        }

        /// <summary>
        /// 处理客户端连接的函数
        /// </summary>
        /// <param name="ar"></param>
        private void HandleTcpClientAccepted(IAsyncResult ar)
        {
            if (IsRunning)
            {
                try
                {
                    TcpClient client = listener.EndAcceptTcpClient(ar);

                    string address = client.Client.RemoteEndPoint.ToString();
                    TcpClientState state = null;
                    //lock (lock_conn)
                    //{
                    //    if (connections.ContainsKey(address))
                    //    {
                    //        state = connections[address];
                    //    }
                    //    else
                    //    {
                    state = new TcpClientState(client);
                    state.Received += State_Received;
                    //        connections.Add(state.Address, state);
                    //    }
                    //}

                    state.Receive();

                    listener.BeginAcceptTcpClient(new AsyncCallback(HandleTcpClientAccepted), ar.AsyncState);
                }
                catch (Exception ex)
                { }
            }
        }

        private void State_Received(string message, TcpClientState state)
        {
            Received?.Invoke(message, state);
        }

        public HResult Send(IPEndPoint remoteEp, MessageBase msg)
        {
            string json = JsonConvert.SerializeObject(msg);

            return Send(remoteEp, json);
        }

        public HResult Send(IPEndPoint remoteEp, string data)
        {
            HResult result = new HResult();
            TcpClient client = new TcpClient();
            try
            {
                var outputBuffer = Encoding.UTF8.GetBytes(data);

                client.Connect(remoteEp);
                var ns = client.GetStream();
                ns.Write(outputBuffer, 0, outputBuffer.Length);
                ns.Close();

                result.success = true;
            }
            catch (Exception ex)
            {
                result.message = ex.Message + (ex.InnerException == null ? "" : ex.InnerException.Message);
                result.success = false;
            }
            finally
            {
                client.Close();
            }

            return result;
        }

        public HResult Send(IPEndPoint remoteEp, byte[] data)
        {
            HResult result = new HResult();
            TcpClient client = new TcpClient();
            try
            {
                var outputBuffer = data;

                client.Connect(remoteEp);
                var ns = client.GetStream();
                System.Threading.Thread.Sleep(1000);
                ns.Write(outputBuffer, 0, outputBuffer.Length);
                ns.Close();

                result.success = true;
            }
            catch (Exception ex)
            {
                result.message = ex.Message + (ex.InnerException == null ? "" : ex.InnerException.Message);
                result.success = false;
            }
            finally
            {
                client.Close();
            }

            return result;
        }

    }

    public class TcpClientState
    {
        public TcpClient TcpClient { get; set; }

        public byte[] Buffer { get; set; }

        public NetworkStream NetworkStream
        {
            get { return TcpClient.GetStream(); }
        }

        public EndPoint RemoteEndPoint
        {
            get { return TcpClient.Client.RemoteEndPoint; }
        }

        public event ReceivedAsyncEventHandler Received;

        private System.IO.MemoryStream ms;

        private const int bufferSize = 1024;

        public TcpClientState(TcpClient client)
        {
            TcpClient = client;
        }

        public void Receive()
        {
            Buffer = new byte[bufferSize];

            //开始异步读取数据
            NetworkStream.BeginRead(Buffer, 0, Buffer.Length, HandleDataReceived, this);
        }

        /// <summary>
        /// 数据接受回调函数
        /// </summary>
        /// <param name="ar"></param>
        private void HandleDataReceived(IAsyncResult ar)
        {
            try
            {
                TcpClientState state = (TcpClientState)ar.AsyncState;
                NetworkStream stream = state.NetworkStream;

                int recv = 0;
                try
                {
                    recv = stream.EndRead(ar);
                }
                catch(Exception ex)
                {
                    recv = 0;
                }

                if (recv > 1)
                {
                    if (ms == null)
                    {
                        ms = new System.IO.MemoryStream();
                    }

                    ms.Write(state.Buffer, 0, recv);

                    Buffer = new byte[bufferSize];

                    stream.BeginRead(state.Buffer, 0, state.Buffer.Length, HandleDataReceived, state);
                }
                else
                {
                    // connection has been closed
                    if (ms != null)
                    {
                        byte[] data = new byte[ms.Length];
                        ms.Seek(0, System.IO.SeekOrigin.Begin);
                        ms.Read(data, 0, data.Length);
                        ms.Close();
                        ms.Dispose();

                        string str = Encoding.UTF8.GetString(data);

                        Received?.Invoke(str, state);
                    }

                    state.Close();
                }
            }
            catch (Exception ex)
            { }
        }

        public void Close()
        {
            //关闭数据的接受和发送
            TcpClient.Close();
            TcpClient.Dispose();
            Buffer = null;
        }

    }
}
